// Package wplog 日志记录接口
// 通过zap实现
package wplog

import (
	"encoding/json"
	"fmt"
	"os"
	"runtime/debug"
	"strings"
	"time"
	"gamesdk/wanyu/server/engine/wpcfg"

	//"wanyu/server/engine/wpcfg"
	"gamesdk/wanyu/server/engine/globaldef/consts"

	"github.com/micro/go-micro/config"
	"github.com/natefinch/lumberjack"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

// Level 日志等级定义
type Level zapcore.Level

var (
	// DebugLevel level
	DebugLevel = Level(zap.DebugLevel)
	// InfoLevel level
	InfoLevel = Level(zap.InfoLevel)
	// WarnLevel level
	WarnLevel = Level(zap.WarnLevel)
	// ErrorLevel level
	ErrorLevel = Level(zap.ErrorLevel)
	// PanicLevel level
	PanicLevel = Level(zap.PanicLevel)
	// FatalLevel level
	FatalLevel = Level(zap.FatalLevel)
)

var (
	options Options
	//logger  *zap.Logger
	dynamicLevel = zap.NewAtomicLevel()

	sugar *zap.SugaredLogger
)

func newEncoderConfig() zapcore.EncoderConfig {
	return zapcore.EncoderConfig{
		// Keys can be anything except the empty string.
		TimeKey:       "T",
		LevelKey:      "L",
		NameKey:       "N",
		CallerKey:     "C",
		MessageKey:    "M",
		StacktraceKey: "S",
		LineEnding:    zapcore.DefaultLineEnding,
		//EncodeLevel:    zapcore.CapitalLevelEncoder,
		EncodeLevel:    zapcore.LowercaseColorLevelEncoder,
		EncodeTime:     timeEncoder,
		EncodeDuration: zapcore.StringDurationEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
	}
}

func timeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
	enc.AppendString(t.Format("2006-01-02 15:04:05.000"))
}

func defaultRawCfg() {
	options.cfgJSON = []byte(`{
		"level": "debug",
		"outputPaths": ["stdout","gameapi.log"],
		"errorOutputPaths": ["stderr"],
		"encoding": "console",
		"encoderConfig": {
			"messageKey": "msg",
			"levelKey": "lvl",
			"levelEncoder": "lowercase"
		}
	}`)
	options.curLevel = DebugLevel
}

func init() {
	//首先读取当前目录的默认配置，如果读取失败则赋默认值
	for i := 0; i < 1; i++ {
		var cfg config.Config
		var err error

		//name := strings.Split(os.Args[0], ".")

		if cfg, err = wpcfg.SyncLoadFile(consts.ConfigServer, os.Args[0]+".json"); err != nil {
			fmt.Println("read cfg file is failed, ec = ", err)
			defaultRawCfg()
			break
		}
		// 得到log配置数据
		outputFile := cfg.Get("logcfg", "outputFile").String("output.log")
		cfgJSON := cfg.Get("logcfg", "cfgParamm").Bytes()
		if "" == outputFile || nil == cfgJSON {
			fmt.Println("parse cfg file is failed")
			defaultRawCfg()
			break
		}

		fmt.Println("read cfg file is success")
		options.cfgJSON = cfgJSON
	}

	rebuildLogger()
}

func initLogger(logpath string, loglevel Level) *zap.Logger {
	w := zapcore.AddSync(&lumberjack.Logger{
		Filename:   logpath, // 输出文件
		MaxSize:    50,      // 日志文件最大大小（单位：MB）
		MaxBackups: 50,      // 保留的旧日志文件最大数量
		MaxAge:     60,      // 保存日期(天)
	})
	core := zapcore.NewCore(
		//zapcore.NewJSONEncoder(newEncoderConfig()), // 日志形式
		//json形式
		//zapcore.NewJSONEncoder(NewEncoderConfig())
		//友好形式
		zapcore.NewConsoleEncoder(newEncoderConfig()),
		//zapcore.NewMultiWriteSyncer( /*zapcore.AddSync(os.Stdout),*/ w), // 日志输出流可以添加多个
		zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), w), // 日志输出流可以添加多个
		dynamicLevel, // 日志等级
	)
	logInst := zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1))
	defer logInst.Sync()

	dynamicLevel.SetLevel(zap.DebugLevel)

	return logInst
}

func InitLogger(opts ...Option) error {

	options = NewOptions(opts...)

	return rebuildLogger()
}

func rebuildLogger() error {
	if err := json.Unmarshal(options.cfgJSON, &(options.config)); err != nil {
		return err
	}

	logger := initLogger(options.config.OutputPaths[1], options.curLevel)
	sugar = logger.Sugar()
	return nil
}

// GetLevel 得到当前日志等级
func GetLevel() Level {
	return options.curLevel
}

//动态设置日志等级，立即生效
func SetLevel(lv Level) {
	dynamicLevel.SetLevel(zapcore.Level(lv))
}

// TraceError 打印堆栈和错误
func TraceError(format string, args ...interface{}) {
	Error(string(debug.Stack()))
	Errorf(format, args...)
}

// ParseLevel 转换字符串到等级
func ParseLevel(s string) Level {
	if strings.ToLower(s) == "debug" {
		return DebugLevel
	} else if strings.ToLower(s) == "info" {
		return InfoLevel
	} else if strings.ToLower(s) == "warn" || strings.ToLower(s) == "warning" {
		return WarnLevel
	} else if strings.ToLower(s) == "error" {
		return ErrorLevel
	} else if strings.ToLower(s) == "panic" {
		return PanicLevel
	} else if strings.ToLower(s) == "fatal" {
		return FatalLevel
	}
	Errorf("ParseLevel: unknown level: %s", s)
	return DebugLevel
}

//Debugf 输出debu
func Debugf(format string, args ...interface{}) {
	//sugar.With(zap.Time("ts", time.Now())).Debugf(format, args...)
	sugar.Debugf(format, args...)
}

//Infof 输出调试级信息
func Infof(format string, args ...interface{}) {
	//sugar.With(zap.Time("ts", time.Now())).Infof(format, args...)
	sugar.Infof(format, args...)
}

//Warnf 输出警告级信息
func Warnf(format string, args ...interface{}) {
	//sugar.With(zap.Time("ts", time.Now())).Warnf(format, args...)
	sugar.Warnf(format, args...)
}

//Errorf 输出错误级信息
func Errorf(format string, args ...interface{}) {
	//sugar.With(zap.Time("ts", time.Now())).Errorf(format, args...)
	sugar.Errorf(format, args...)
}

//Panicf 输出严重信息
func Panicf(format string, args ...interface{}) {
	//sugar.With(zap.Time("ts", time.Now())).Panicf(format, args...)
	sugar.Panicf(format, args...)
}

//Fatalf 输出最严重信息
func Fatalf(format string, args ...interface{}) {
	Error(string(debug.Stack()))
	//sugar.With(zap.Time("ts", time.Now())).Fatalf(format, args...)
	sugar.Fatalf(format, args...)
}

//Debug 输出debu
func Debug(args ...interface{}) {
	//sugar.With(zap.Time("ts", time.Now())).Error(args...)
	sugar.Debug(args...)
}

//Infof 输出调试级信息
func Info(args ...interface{}) {
	//sugar.With(zap.Time("ts", time.Now())).Error(args...)
	sugar.Info(args...)
}

//Warnf 输出警告级信息
func Warn(args ...interface{}) {
	//sugar.With(zap.Time("ts", time.Now())).Error(args...)
	sugar.Warn(args...)
}

//Error 输出错误级信息
func Error(args ...interface{}) {
	//sugar.With(zap.Time("ts", time.Now())).Error(args...)
	sugar.Error(args...)
}

//Panic 输出严重信息
func Panic(args ...interface{}) {
	//sugar.With(zap.Time("ts", time.Now())).Panic(args...)
	sugar.Panic(args...)
}

//Fatal 输出最严重信息
func Fatal(args ...interface{}) {
	//sugar.With(zap.Time("ts", time.Now())).Fatal(args...)
	sugar.Fatal(args...)
}

//Options 日志选项
type Options struct {
	config   zap.Config
	source   string
	curLevel Level
	cfgJSON  []byte
}

//Option 选项设置接口
type Option func(o *Options)

//WithSource 设置source
func WithSource(source string) Option {
	return func(o *Options) {
		o.source = source
	}
}

//WithOutput 设置输出
func WithOutput(output string) Option {
	return func(o *Options) {
		o.config.OutputPaths = append(o.config.OutputPaths, output)
	}
}

//WithLevel 设置日志等级
func WithLevel(lvl Level) Option {
	return func(o *Options) {
		o.curLevel = lvl
	}
}

//WithCfg 设置配置数据
func WithCfg(cfg []byte) Option {
	return func(o *Options) {
		if cfg != nil && len(cfg) > 0 {
			o.cfgJSON = cfg
		}
	}
}

//NewOptions 根据数据创建选项
func NewOptions(opts ...Option) Options {
	options := Options{
		curLevel: DebugLevel,
		cfgJSON: []byte(`{
			"level": "debug",
			"outputPaths": ["stderr"],
			"errorOutputPaths": ["stderr"],
			"encoding": "console",
			"encoderConfig": {
				"messageKey": "message",
				"levelKey": "level",
				"levelEncoder": "lowercase"
			}
		}`),
	}

	for _, o := range opts {
		o(&options)
	}

	return options
}
